﻿using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using Kyoh.Lib.Win32API.Shell;

namespace Kyoh.Lib.Win32API
{
    /// <summary><see cref="NativeMethods.EnumWindows"/> メソッド呼出しに使用するコールバック関数のハンドラを定義します。</summary>
    /// <param name="hWnd">列挙されたウィンドウごとのウィンドウハンドル。</param>
    /// <param name="lParam"><see cref="NativeMethods.EnumWindows"/> メソッド呼出し時に指定したアプリケーション定義の値。</param>
    /// <returns>列挙を続ける場合には <c>true</c> を返却してください。列挙を中止する場合は、 <c>false</c> を返却してください。</returns>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate bool EnumWindowCallback(IntPtr hWnd, int lParam);

    /// <summary>Win32APIのP/Invoke呼出しメソッド群を定義します。</summary>
    public static class NativeMethods
    {
        /// <summary>指定されたウィンドウのクライアント領域または画面全体を表すディスプレイデバイスコンテキストのハンドルを取得します。</summary>
        /// <param name="hWnd">デバイスコンテキストの取得対象となるウィンドウのハンドルを指定します。<c>IntPtr.Zero</c> を指定すると、<see cref="GetDC"/> は画面全体を表すデバイスコンテキストを取得します。</param>
        /// <returns>関数が成功すると、指定したウィンドウのクライアント領域を表すデバイスコンテキストのハンドルが返ります。関数が失敗すると、<c>IntPtr.Zero</c> が返ります。</returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr GetDC(IntPtr hWnd);

        /// <summary>指定されたデバイスと互換性のあるメモリデバイスコンテキストを作成します。</summary>
        /// <param name="hdc">既存のデバイスコンテキストのハンドルを指定します。<c>IntPtr.Zero</c> を指定すると、アプリケーションの現在の画面と互換性のあるメモリデバイスコンテキストが作成されます。</param>
        /// <returns>関数が成功すると、作成されたメモリデバイスコンテキストのハンドルが返ります。関数が失敗すると、<c>IntPtr.Zero</c> が返ります。</returns>
        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CreateCompatibleDC(IntPtr hdc);

        /// <summary>指定されたデバイスコンテキストで、指定された 1 個のオブジェクトを選択します。新しいオブジェクトは、同じタイプの以前のオブジェクトを置き換えます。</summary>
        /// <param name="hdc">デバイスコンテキストのハンドルを指定します。</param>
        /// <param name="hgdiobj">選択対象のオブジェクトのハンドルを指定します。</param>
        /// <returns>リージョン以外のオブジェクトを指定した場合に関数が成功すると、置き換えが発生する前のオブジェクトのハンドルが返ります。</returns>
        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

        /// <summary>デバイスコンテキストを解放し、他のアプリケーションからつかえるようにします。ReleaseDC 関数の効果は、デバイスコンテキストのタイプによって異なります。この関数は、共通デバイスコンテキストとウィンドウデバイスコンテキストだけを解放します。クラスデバイスコンテキストやプライベートデバイスコンテキストには効果がありません。</summary>
        /// <param name="hWnd">解放対象のデバイスコンテキストに対応するウィンドウのハンドルを指定します。</param>
        /// <param name="hDC">解放対象のデバイスコンテキストのハンドルを指定します。</param>
        /// <returns>戻り値は、デバイスコンテキストを解放したかどうかを示します。デバイスコンテキストが解放された場合、<c>1</c> が返ります。デバイスコンテキストが解放されなかった場合、<c>0</c> が返ります。</returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

        /// <summary>ペン、ブラシ、フォント、ビットマップ、リージョン、パレットのいずれかの論理オブジェクトを削除し、そのオブジェクトに関連付けられていたすべてのシステムリソースを解放します。オブジェクトを削除した後は、指定されたハンドルは無効になります。</summary>
        /// <param name="hobject">ペン、ブラシ、フォント、ビットマップ、リージョン、パレットのいずれかの論理オブジェクトのハンドルを指定します。</param>
        /// <returns>関数が成功すると、<c>0</c> 以外の値が返ります。指定したハンドルが有効でない場合、またはデバイスコンテキストでそのオブジェクトが選択されている場合は、<c>0</c> が返ります。</returns>
        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int DeleteObject(IntPtr hobject);

        /// <summary>指定されたデバイスコンテキストを削除します。</summary>
        /// <param name="hdc">デバイスコンテキストのハンドルを指定します。</param>
        /// <returns>関数が成功すると、<c>0</c> 以外の値が返ります。関数が失敗すると、<c>0</c> が返ります。</returns>
        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int DeleteDC(IntPtr hdc);

        /// <summary>レイヤードウィンドウの位置、サイズ、形、内容、透明度を更新します。</summary>
        /// <param name="hwnd">レイヤードウィンドウのハンドル。</param>
        /// <param name="hdcDst">画面のデバイスコンテキストのハンドル。</param>
        /// <param name="pptDst">画面の新しい位置。</param>
        /// <param name="psize">レイヤードウィンドウの新しいサイズ。</param>
        /// <param name="hdcSrc">サーフェスのデバイスコンテキストのハンドル。</param>
        /// <param name="pptSrc">レイヤの位置。</param>
        /// <param name="crKey">カラーキー。</param>
        /// <param name="pblend">ブレンド機能。</param>
        /// <param name="dwFlags">透明度。</param>
        /// <returns></returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int UpdateLayeredWindow(
            IntPtr hwnd,
            IntPtr hdcDst,
            [In] ref Point pptDst,
            [In] ref Size psize,
            IntPtr hdcSrc,
            [In] ref Point pptSrc,
            int crKey,
            [In] ref BlendFunction pblend,
            UpdateLayeredWindowFlags dwFlags);

        /// <summary>コンソールを作成</summary>
        [DllImport("kernel32.dll")]
        public static extern Boolean AllocConsole();

        /// <summary>Attaches the calling process to the console of the specified process.</summary>
        [DllImport("kernel32.dll"), CLSCompliant(false)]
        public static extern Boolean AttachConsole(uint dwProcessId);

        /// <summary>コンソールを解放します。</summary>
        [DllImport("kernel32.dll")]
        public static extern Boolean FreeConsole();

        /// <summary>Retrieves the window handle used by the console associated with the calling process.</summary>
        [DllImport("kernel32.dll")]
        public static extern IntPtr GetConsoleWindow();

        /// <summary>Windowsが実行されてから経過した時間(ミリ秒単位)を取得します。</summary>
        [DllImport("kernel32.dll"), CLSCompliant(false)]
        public static extern uint GetTickCount();

        /// <summary>既存のプロセスオブジェクトのハンドルを開きます。</summary>
        [DllImport("kernel32.dll"), CLSCompliant(false)]
        public static extern IntPtr OpenProcess([MarshalAs(UnmanagedType.U4)] DesiredAccess desiredAccess,
                                                [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int processId);

        /// <summary>指定されたプロセスのメモリ領域からデータを読み取ります。</summary>
        [DllImport("kernel32.dll"), CLSCompliant(false)]
        public static extern bool ReadProcessMemory(IntPtr processId, IntPtr baseAddress, IntPtr buffer, IntPtr size,
                                                    IntPtr numberOfBytesRead);

        /// <summary>指定されたプロセスの仮想アドレス空間内のメモリ領域の予約とコミットの一方または両方を行います。</summary>
        [DllImport("kernel32.dll"), CLSCompliant(false)]
        public static extern IntPtr VirtualAllocEx(IntPtr processId, IntPtr lpAddress, IntPtr size, uint allocationType,
                                                   uint flProtect);

        /// <summary>指定されたプロセスの仮想アドレス空間内のメモリ領域を解放またはコミット解除します。</summary>
        [DllImport("kernel32.dll"), CLSCompliant(false)]
        public static extern bool VirtualFreeEx(IntPtr processId, IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);

        /// <summary>指定されたプロセスのメモリ領域にデータを書き込みます。</summary>
        [DllImport("kernel32.dll"), CLSCompliant(false)]
        public static extern bool WriteProcessMemory(IntPtr processId, IntPtr baseAddress, IntPtr buffer, IntPtr size,
                                                     IntPtr numberOfBytesWritten);

        /// <summary>1 つのデスクトップ上のすべてのウィンドウを列挙します。</summary>
        [DllImport("user32.dll", EntryPoint = "EnumDesktopWindows", ExactSpelling = false, CharSet = CharSet.Auto,
            SetLastError = true)]
        public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowCallback lpfn, IntPtr lParam);

        /// <summary>画面上のすべてのトップレベルウィンドウを列挙します。</summary>
        [DllImport("user32.dll", EntryPoint = "EnumWindows", ExactSpelling = false, CharSet = CharSet.Auto,
            SetLastError = true)]
        public static extern bool EnumWindows(EnumWindowCallback enumProc, IntPtr lParam);

        /// <summary>ウィンドウを検索し、指定された文字列と一致するクラス名とウィンドウ名を持つトップレベルウィンドウのハンドルを取得します。</summary>
        [DllImport("user32.dll", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
        public static extern IntPtr FindWindow(string className, string windowName);

        /// <summary>ウィンドウを検索し、指定された文字列と一致するクラス名とウィンドウ名文字列を持つウィンドウのハンドルを取得します。</summary>
        [DllImport("user32.dll", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
        public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string className,
                                                 string windowText);

        /// <summary>ウィンドウが属するクラスの名前を取得します。</summary>
        [DllImport("user32.dll", EntryPoint = "GetClassNameW", CharSet = CharSet.Auto)]
        public static extern int GetClassName(IntPtr hWnd,
                                              [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder className,
                                              int maxCount);

        /// <summary>デスクトップウィンドウのハンドルを取得します。</summary>
        [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
        public static extern IntPtr GetDesktopWindow();

        /// <summary>フォアグラウンドウィンドウのハンドルを取得します。</summary>
        [DllImport("user32.dll")]
        public static extern IntPtr GetForegroundWindow();

        /// <summary>最後に発生したキー入力イベントの時刻を取得します。</summary>
        [DllImport("user32.dll")]
        public static extern bool GetLastInputInfo(ref LastInputInfo plii);

        /// <summary>指定ウィンドウと関係のある(Zオーダー、またはオーナー)ウィンドウのハンドルを取得します。</summary>
        [DllImport("user32.dll", EntryPoint = "GetWindow")]
        public static extern IntPtr GetWindow(IntPtr hWnd, [MarshalAs(UnmanagedType.U4)] GetWindowType uCmd);

        /// <summary>ウィンドウの各種情報を取得します。</summary>
        [DllImport("user32.dll", EntryPoint = "GetWindowInfo")]
        public static extern bool GetWindowInfo(IntPtr hwnd, ref WindowInfo pwi);

        /// <summary>ウィンドウハンドルに関連付けられたモジュールの完全パスとファイル名を取得します。</summary>
        [DllImport("user32.dll", EntryPoint = "GetWindowModuleFileNameW"), CLSCompliant(false)]
        public static extern uint GetWindowModuleFileName(IntPtr hwnd,
                                                          [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder
                                                              pszFileName, uint cchFileNameMax);

        /// <summary>ウィンドウの左上端と右下端の座標をスクリーン座標で取得します。</summary>
        [DllImport("user32.dll", EntryPoint = "GetWindowRect")]
        public static extern bool GetWindowRect(IntPtr hWndr, out Rectangle rectangle);

        /// <summary>ウィンドウのタイトルバーのテキストを取得します。</summary>
        [DllImport("user32.dll", EntryPoint = "GetWindowTextW", CharSet = CharSet.Auto)]
        public static extern int GetWindowText(IntPtr hWnd, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder caption,
                                               int maxCount);

        /// <summary>ウィンドウを作成したスレッドのIDを取得します。</summary>
        [DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", CharSet = CharSet.Auto)]
        public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId);

        /// <summary>ウィンドウが表示状態であるかどうかを取得します。</summary>
        [DllImport("user32.dll", EntryPoint = "IsWindowVisible")]
        public static extern bool IsWindowVisible(IntPtr hWnd);

        /// <summary>スレッドのメッセージ キューにメッセージを追加します。</summary>
        [DllImport("user32.dll", EntryPoint = "PostMessage"), CLSCompliant(false)]
        public static extern int PostMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

        /// <summary>スレッドのメッセージ キューにメッセージを追加します。</summary>
        [DllImport("user32.dll", EntryPoint = "PostMessage"), CLSCompliant(false)]
        public static extern int PostMessage(IntPtr hWnd, int msg, IntPtr wParam, ref CopyData lParam);

        /// <summary>新しい一意なウィンドウメッセージを定義します。</summary>
        [DllImport("user32.dll", EntryPoint = "RegisterWindowMessage", BestFitMapping = false,
            ThrowOnUnmappableChar = true)]
        public static extern int RegisterWindowMessage([MarshalAs(UnmanagedType.LPStr)] string lpString);

        /// <summary>SendMessageにより送られたメッセージに応答します。</summary>
        [DllImport("user32.dll")]
        public static extern int ReplyMessage(IntPtr lResult);

        /// <summary>メッセージをウィンドウプロシージャに送ります。</summary>
        [DllImport("user32.dll", EntryPoint = "SendMessage"), CLSCompliant(false)]
        public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

        /// <summary>メッセージをウィンドウプロシージャに送ります。</summary>
        [DllImport("user32.dll", EntryPoint = "SendMessage"), CLSCompliant(false)]
        public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref CopyData lParam);

        /// <summary>メッセージをウィンドウプロシージャに送ります。</summary>
        [DllImport("user32.dll", EntryPoint = "SendMessageTimeout"), CLSCompliant(false)]
        public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam,
                                                       SendMessageTimeoutFlags fuFlags, uint uTimeout, IntPtr lpdwResult);

        /// <summary>ウィンドウのサイズ、位置、およびZオーダーを変更します。</summary>
        [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "SetWindowPos"), CLSCompliant(false)]
        public static extern bool SetWindowPos(IntPtr hWnd, SetWindowZOrder hWndInsertAfter, int x, int y, int cx,
                                               int cy, SetWindowPositionFlags uFlags);

        /// <summary>ウィンドウの表示状態を設定します。</summary>
        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, ShowWindowFlags flags);

        /// <summary>ファイルシステム上のファイル、ディレクトリ等に関する各種情報を取得します。</summary>
        [DllImport("shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, EntryPoint = "SHGetFileInfoW"),
         CLSCompliant(false)]
        public static extern IntPtr ShGetFileInfo(string pszPath, FileAttributesFlags dwFileAttributes,
                                                  ref Shell.ShFileInfoW psfi, uint cbSizeFileInfo,
                                                  Shell.ShellFileInfoFlags uFlags);
        /// <summary>ファイルシステム上のファイル、ディレクトリ等に関する各種情報を取得します。</summary>
        [DllImport("shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, EntryPoint = "SHGetFileInfoW"),
         CLSCompliant(false)]
        public static extern IntPtr ShGetFileInfo(IntPtr pidl, FileAttributesFlags dwFileAttributes,
                                                  ref Shell.ShFileInfoW psfi, uint cbSizeFileInfo,
                                                  Shell.ShellFileInfoFlags uFlags);
        /// <summary>特殊フォルダのPIDLを取得します。</summary>
        [DllImport("Shell32.DLL")]
        public static extern int SHGetSpecialFolderLocation(
                    IntPtr hwndOwner, ShellSpecialFolderConstants nFolder, out IntPtr ppidl);

        /// <summary>特殊フォルダのパスを取得します。</summary>
        [DllImport("Shell32.DLL")]
        public static extern int SHGetSpecialFolderPath(IntPtr hwndOwner, [Out] StringBuilder lpszPath, int nFolder, [MarshalAs(UnmanagedType.Bool)]bool fCreate);

        [DllImport("shell32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SHGetPathFromIDList(IntPtr pidl, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder pszPath);

        [DllImport("shell32.dll")]
        public static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken,
           uint dwFlags, [Out] StringBuilder pszPath);

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool DestroyIcon(IntPtr hIcon);

    }
}